package cn.getech.data.development.service.impl;

import cn.getech.data.development.constant.PermissionTypeEnum;
import cn.getech.data.development.entity.BdpDataCategory;
import cn.getech.data.development.entity.TableInfo;
import cn.getech.data.development.entity.flink.BdpRealTableInfo;
import cn.getech.data.development.mapper.BdpDataCategoryMapper;
import cn.getech.data.development.model.dto.ProjectListDTO;
import cn.getech.data.development.model.dto.real.RealTableQueryDTO;
import cn.getech.data.development.model.dto.real.RealTableQueryReturnDTO;
import cn.getech.data.development.model.vo.BdpDataCategoryTableInfoVO;
import cn.getech.data.development.service.BdpDataCategoryService;
import cn.getech.data.development.utils.DataPermissionUtil;
import cn.getech.data.intelligence.common.utils.PageUtils;
import cn.getech.system.center.entity.SysUserEntity;
import cn.getech.system.center.mapper.SysUserMapper;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.reflect.FieldUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * 类目信息表Service接口实现
 *
 * @author bianj
 * @version 1.0.0 2020-09-29
 */
@Service
@Transactional
public class BdpDataCategoryServiceImpl extends ServiceImpl<BdpDataCategoryMapper, BdpDataCategory> implements BdpDataCategoryService {

    private static final Logger logger = LoggerFactory.getLogger(BdpDataCategoryService.class);

    @Autowired
    private BdpDataCategoryMapper bdpDataCategoryMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    /**
     * 获取类目层级列表
     *
     * @return
     */
    @Override
    public List<BdpDataCategory> findBdpDataCategoryByCondition() {
        Integer tenantId = ShiroUtils.getTenantId();
        List<BdpDataCategory> list = this.bdpDataCategoryMapper.selectList(new QueryWrapper<BdpDataCategory>()
                .eq(tenantId != null, "tenant_id", tenantId));
        try {
            return getTree(list, "id");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public BdpDataCategory getCategoryName(String CategoryName) {
        List<BdpDataCategory> category_name = bdpDataCategoryMapper.selectList(new QueryWrapper<BdpDataCategory>().like("category_name", CategoryName));
        if (category_name != null && category_name.size() > 0) {
            return category_name.get(0);
        }
        return null;
    }

    /**
     * 根据类目ID查询类目信息下表的信息
     *
     * @param paster 主键ID
     * @return
     */
    @Override
    public PageUtils getBdpDataCategoryById(Map<String, Object> paster) {
        int page = 1;
        int limit = 10;
        if (paster.get("page") != null) {
            page = Integer.parseInt(paster.get("page") + "");
        }
        if (paster.get("limit") != null) {
            limit = Integer.parseInt(paster.get("limit") + "");
        }
        String tableType = (String) paster.get("tableType");
        String dbName = (String) paster.get("dbName");
        String proName = (String) paster.get("name");
        String tableName = (String) paster.get("tableName");
        String id = (String) paster.get("id");
        String projectId = (String) paster.get("projectId");
        Integer tenantId = ShiroUtils.getTenantId();
        paster.put("tenantId", tenantId);
        IPage<BdpDataCategoryTableInfoVO> page1 = new Page<>(page, limit);
        if (StringUtils.isNotBlank(dbName) || StringUtils.isNotBlank(proName)
                || StringUtils.isNotBlank(tableName) || StringUtils.isNotBlank(tableType)
                || StringUtils.isNotBlank(id) || StringUtils.isNotBlank(projectId)) {
            page1 = bdpDataCategoryMapper.selectPageList(page1, paster);
        } else {
            page1 = bdpDataCategoryMapper.selectByPage(page1, tableType, tenantId);
        }
        if (CollectionUtil.isEmpty(page1.getRecords())) {
            return new PageUtils(page1);
        }
        for (BdpDataCategoryTableInfoVO record : page1.getRecords()) {
            record.setId(record.getTableId());
            Integer tableId = record.getTableId();
            ArrayList<String> categoryNames = bdpDataCategoryMapper.selectCategoryName(tableId,tenantId);
            record.setCategoryName(categoryNames);
            //离线
            if (record.getTableType().equals(1)) {
                TableInfo tableInfo = bdpDataCategoryMapper.selectTables(tableId);
                if (Objects.nonNull(tableInfo)) {
                    record.setTableName(tableInfo.getTableName());
                    record.setDbName(tableInfo.getDbName());
                    record.setTableAlias(tableInfo.getTableAlias());
                    record.setDesc(tableInfo.getDesc());
                    //record.setCreateTime(tableInfo.getCreateTime());
                    if (tableInfo.getStoreEngine() != null) {
                        if (tableInfo.getStoreEngine().equals(1)) {
                            record.setTypeid("hive");
                        }
                        if (tableInfo.getStoreEngine().equals(2)) {
                            record.setTypeid("kudu");
                        }
                    }
                }
                ArrayList<String> proNames = bdpDataCategoryMapper.selectProName(tableId, record.getTableType());
                record.setProName(proNames);
            }
            //实时
            if (record.getTableType().equals(2)) {
                BdpRealTableInfo realTableInfo = bdpDataCategoryMapper.selectRealTableInfo(tableId);
                Integer resourceId = null;
                if (Objects.nonNull(realTableInfo)) {
                    record.setTableName(realTableInfo.getTableName());
                    record.setDbName(realTableInfo.getDbName());
                    record.setTableDesc(realTableInfo.getTableDesc());
                    //record.setCreateTime(realTableInfo.getCreateTime());
                    resourceId = realTableInfo.getResourceId();
                }
                //内部表
                ArrayList<String> proNames = null;
                if (Objects.isNull(resourceId)) {
                    proNames = bdpDataCategoryMapper.selectProName(tableId, record.getTableType());
                } else {
                    // proNames = bdpDataCategoryMapper.selectProNameByResourceId(resourceId);
                }
                record.setProName(proNames);
                record.setCategoryName(categoryNames);
                record.setTypeid("kafka");
            }
        }
        return new PageUtils(page1);
    }

    /**
     * 根据类目ID查询不在类目表下的表
     *
     * @param params 主键ID
     * @return
     */
    @Override
    public PageUtils getNotBdpDataCategoryById(Map<String, Object> params) {
        int page = 1;
        int limit = 10;
        if (params.get("limit") != null) {
            limit = Integer.parseInt(params.get("limit") + "");
        }
        if (params.get("page") != null) {
            page = Integer.parseInt(params.get("page") + "");
        }
        params.put("page", (page - 1) * limit);
        params.put("limit", limit);
        wrapOfflineParams(params);
        List<BdpDataCategoryTableInfoVO> bdpDataCategoryTableInfoVOS = bdpDataCategoryMapper.selectListByNotTableInfo(params);
        for (BdpDataCategoryTableInfoVO tableInfoVO : bdpDataCategoryTableInfoVOS) {
            ArrayList<String> projectNames = bdpDataCategoryMapper.getProjectNamesByTableId(tableInfoVO.getId());
            tableInfoVO.setProName(projectNames);
        }
        Integer integer = bdpDataCategoryMapper.selectListByNotTableInfoCount(params);
        return new PageUtils<>(bdpDataCategoryTableInfoVOS, integer, limit, page);
    }


    /**
     * 添加类目录信息
     *
     * @param bdpDataCategory 类目信息表信息
     * @return
     */
    @Transactional
    @Override
    public boolean addBdpDataCategory(BdpDataCategory bdpDataCategory) {
        Long userId = ShiroUtils.getUserId();
        if (userId == null) {
            userId = 1L;
        }
        if (bdpDataCategory.getParentId() == null) {
            bdpDataCategory.setLevel(1);
        } else {
            bdpDataCategory.setLevel(bdpDataCategory.getLevel() + 1);
        }
        bdpDataCategory.setTenantId(ShiroUtils.getTenantId());
        /**判断当前级别类目是否有重名的类目*/
        BdpDataCategory bdpDataCategory1 = bdpDataCategoryMapper.selectOne(new QueryWrapper<BdpDataCategory>().eq("category_name", bdpDataCategory.getCategoryName()).eq("level", bdpDataCategory.getLevel()));
        if (bdpDataCategory1 == null) {
            /**判断数据是否正确*/
            if (bdpDataCategory.getParentId() != null) {
                /**判断是否有父节点*/
                BdpDataCategory id = bdpDataCategoryMapper.selectOne(new QueryWrapper<BdpDataCategory>().eq("id", bdpDataCategory.getParentId()));
                if (id != null) {
                    bdpDataCategory.setCreateTime(new Date());
                    bdpDataCategory.setCreatePer(userId.intValue());
                    return this.save(bdpDataCategory);
                }
            } else {
                bdpDataCategory.setCreateTime(new Date());
                bdpDataCategory.setCreatePer(userId.intValue());
                return this.save(bdpDataCategory);
            }
        }
        return false;
    }

    @Transactional
    @Override
    public boolean updateBdpDataCategory(BdpDataCategory bdpDataCategory) {
        BdpDataCategory bdpDataCategory1 = bdpDataCategoryMapper.selectOne(new QueryWrapper<BdpDataCategory>().eq("category_name", bdpDataCategory.getCategoryName()).eq("level", bdpDataCategory.getLevel()));
        /**判断当前级别类目是否有重名的类目*/
        if (bdpDataCategory1 == null) {
            bdpDataCategory.setUpdateTime(new Date());
            return this.updateById(bdpDataCategory);
        } else {
            if (bdpDataCategory1.getId().equals(bdpDataCategory.getId())) {
                return true;
            }
        }
        return false;
    }

    @Transactional
    @Override
    public int deleteBdpDataCategoryById(Integer id) {
        Map<String, Object> hashMap = new HashMap();
        hashMap.put("id", id);
        /**判断类目下是否有表数据*/
        List<Integer> integers = bdpDataCategoryMapper.selectDataCategory(hashMap);
        /**存在数据返回 false*/
        if (integers != null && integers.size() > 0) {
            return 1;
        } else {
            List<BdpDataCategory> parent_id = bdpDataCategoryMapper.selectList(new QueryWrapper<BdpDataCategory>().eq("parent_id", id));
            /***存在子目录*/
            if (parent_id != null && parent_id.size() > 0) {
                return 2;
            }
        }
        this.removeById(id);
        return 3;
    }

    @Override
    public boolean ifataCategoryBastInfo(String id) {
        Map<String, Object> hashMap = new HashMap();
        hashMap.put("id", id);
        /**判断类目下是否有表数据*/
        List<Integer> integers = bdpDataCategoryMapper.selectDataCategory(hashMap);
        /**存在数据返回 false*/
        if (integers != null && integers.size() > 0) {
            return false;
        } else {
            /**判断是否有子目录*/
            BdpDataCategory parent_id = bdpDataCategoryMapper.selectOne(new QueryWrapper<BdpDataCategory>().eq("parent_id", id));
            /***存在子目录*/
            if (parent_id != null) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean saveBdpDataCategoryByIds(BdpDataCategoryTableInfoVO idList) {
        Long userId = ShiroUtils.getUserId();
        if (userId == null) {
            userId = 1L;
        }
        List<BdpDataCategoryTableInfoVO> bdpDataCategoryTableInfoVOS = new ArrayList<>();
        ArrayList<String> tabinfoId = idList.getTabinfoIds();
        ArrayList<Integer> categoryIds = idList.getCategoryIds();
        for (Integer integ : categoryIds) {
            for (String str : tabinfoId) {
                BdpDataCategoryTableInfoVO bdpDataCategoryTableInfoVO = new BdpDataCategoryTableInfoVO();
                /***保存之前做幂等性校验*/
                Map<String, Object> hashMap = new HashMap();
                hashMap.put("tableId", str);
                hashMap.put("categoryId", integ);
                Integer integer = bdpDataCategoryMapper.selectCategoryTableCount(hashMap);
                if (integer > 0) {
                    continue;
                }
                /**设置类目id*/
                bdpDataCategoryTableInfoVO.setId(integ);
                bdpDataCategoryTableInfoVO.setTabinfoId(str);
                bdpDataCategoryTableInfoVO.setCreatePer(userId.intValue());
                bdpDataCategoryTableInfoVO.setCreateTime(new Date());
                bdpDataCategoryTableInfoVO.setTableType(idList.getTableType());
                bdpDataCategoryTableInfoVOS.add(bdpDataCategoryTableInfoVO);
            }
        }
        if (bdpDataCategoryTableInfoVOS != null && bdpDataCategoryTableInfoVOS.size() > 0) {
            bdpDataCategoryMapper.saveBdpDataCategoryByIds(bdpDataCategoryTableInfoVOS);
            return true;
        }
        return true;
    }

    @Override
    public boolean deleteBdpDataCategoryByIds(BdpDataCategoryTableInfoVO idList) {
        List<BdpDataCategoryTableInfoVO> bdpDataCategoryTableInfoVOS = new ArrayList<>();
        ArrayList<String> tabinfoId = idList.getTabinfoIds();
        for (String str : tabinfoId) {
            BdpDataCategoryTableInfoVO bdpDataCategoryTableInfoVO = new BdpDataCategoryTableInfoVO();
            /**设置类目id*/
            bdpDataCategoryTableInfoVO.setId(idList.getId());
            /**设置表id*/
            bdpDataCategoryTableInfoVO.setTabinfoId(str);
            bdpDataCategoryTableInfoVOS.add(bdpDataCategoryTableInfoVO);
        }
//      Long userId = ShiroUtils.getUserId();
//                List<Integer> authorization = filterAuthorization(userId, "2");
//                /**交集*/
//                List<BdpDataCategoryTableInfoVO> collect = bdpDataCategoryTableInfoVOS.stream().filter(item -> {
//                    if (authorization != null && authorization.size() > 0) {
//                        for (Integer str : authorization) {
//                            if (str.toString().equals(item.getTabinfoId())) {
//                                return true;
//                            }
//                        }
//                    }
//                    return false;
//                }).collect(Collectors.toList());
//                if (collect != null && collect.size() > 0) {
//                    bdpDataCategoryMapper.deleteBdpDataCategoryByIds(collect);
//                    return true;
//                }
        bdpDataCategoryMapper.deleteBdpDataCategoryByIds(bdpDataCategoryTableInfoVOS);
        return true;
    }

    private void wrapOfflineParams(Map<String, Object> params) {
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        List<Integer> integers = DataPermissionUtil.getDataIds(
                userId.intValue(),
                PermissionTypeEnum.STORE.getType(),
                PermissionTypeEnum.QUERY.getType());
        if (integers != null && integers.size() > 0) {
            params.put("ids", integers);
        } else {
            integers.add(-1);
            params.put("ids", integers);
        }
        params.put("userId", userId);
        params.put("tenantId", tenantId);
    }

    private void wrapRealParams(Map<String, Object> params) {
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        params.put("tenantId", tenantId);
        params.put("userId", userId);
        List<Integer> ids = DataPermissionUtil.getDataIds(
                userId.intValue(),
                PermissionTypeEnum.REAL_TABLE.getType(),
                PermissionTypeEnum.QUERY.getType());
        if (CollectionUtil.isNotEmpty(ids)) {
            params.put("ids", ids);
        } else {
            ids.add(-1);
            params.put("ids", ids);
        }
        /***获取实时外部表的数据查询权限（根据角色拥有的数据源权限查询）*/
        List<Integer> resourceIds = DataPermissionUtil.getDataIds(PermissionTypeEnum.RESOURCE.getType(),
                PermissionTypeEnum.QUERY.getType());
        if (CollectionUtils.isEmpty(resourceIds)) {
            resourceIds.add(-1);//无权限
        }
        params.put("resourceIds", resourceIds);
    }

    @Override
    public Set<String> getProcNameList(Map<String, Object> params) {
        Set<String> proNames = new HashSet<>();
        String tableType = (String) params.get("tableType");
        //离线
        if ("1".equals(tableType)) {
            wrapOfflineParams(params);
            Set<String> proName = bdpDataCategoryMapper.getProjectByTableId(params);
            proNames.addAll(proName);
        }
        //实时
        if ("2".equals(tableType)) {
            wrapRealParams(params);
            Set<String> proName = bdpDataCategoryMapper.selectRealProName(params);
            proNames.addAll(proName);
        }
        return proNames;
    }

    @Override
    public List<String> getTableInfoCrateName(Map<String, Object> params) {
        List<String> stringList = new ArrayList<>();
        String tableType = (String) params.get("tableType");
        //离线
        List<Long> createUsers = new ArrayList<>();
        if (tableType != null && tableType.equals("1")) {
            wrapOfflineParams(params);
            createUsers = bdpDataCategoryMapper.getTableInfoCrateName(params);
        }
        if (tableType != null && tableType.equals("2")) {
            wrapRealParams(params);
            createUsers = bdpDataCategoryMapper.getRealTableUsers(params);
        }
        if (CollectionUtil.isEmpty(createUsers)) {
            return stringList;
        }
        List<SysUserEntity> userEntities = sysUserMapper.selectList(new LambdaQueryWrapper<SysUserEntity>()
                .in(SysUserEntity::getUserId, createUsers));
        if (CollectionUtil.isNotEmpty(userEntities)) {
            stringList = userEntities.stream().map(SysUserEntity::getUsername).collect(Collectors.toList());
        }
        return stringList;


    }


    @Override
    public List<String> getDBTableList(Map<String, Object> params) {
        int page = 1;
        int limit = 10;
        if (params.get("page") != null) {
            page = Integer.parseInt(params.get("page") + "");
        }
        if (params.get("limit") != null) {
            limit = Integer.parseInt(params.get("limit") + "");
        }
        params.put("page", (page - 1) * limit);
        params.put("limit", limit);
        return bdpDataCategoryMapper.selectDBTable(params);
    }

    /**
     * 把列表转换为树结构
     *
     * @param originalList 原始list数据
     * @param keyName      作为唯一标示的字段名称
     * @return 组装后的集合
     */
    public static <T> List<T> getTree(List<T> originalList, String keyName) throws Exception {
        String parentFieldName = "parentId";
        String childrenFieldName = "children";
        /***获取根节点，即找出父节点为空的对象*/
        List<T> topList = new ArrayList<>();
        for (int i = 0; i < originalList.size(); i++) {
            T t = originalList.get(i);
            String parentId = BeanUtils.getProperty(t, parentFieldName);
            /***父节点为空*/
            if (StringUtils.isBlank(parentId)) {
                topList.add(t);
            }
        }
        /***将根节点从原始list移除，减少下次处理数据*/
        originalList.removeAll(topList);
        /**递归封装树*/
        fillTree(topList, originalList, keyName, parentFieldName, childrenFieldName);
        return topList;
    }

    /**
     * 封装树
     *
     * @param parentList        要封装为树的父对象集合
     * @param originalList      原始list数据
     * @param keyName           作为唯一标示的字段名称
     * @param parentFieldName   模型中作为parent字段名称
     * @param childrenFieldName 模型中作为children的字段名称
     */
    public static <T> void fillTree(List<T> parentList, List<T> originalList, String keyName, String parentFieldName, String childrenFieldName) throws Exception {
        for (int i = 0; i < parentList.size(); i++) {
            List<T> children = fillChildren(parentList.get(i), originalList, keyName, parentFieldName, childrenFieldName);
            if (children.isEmpty()) {
                continue;
            }
            originalList.removeAll(children);
            fillTree(children, originalList, keyName, parentFieldName, childrenFieldName);
        }
    }

    /**
     * 封装子对象
     *
     * @param parent            父对象
     * @param originalList      待处理对象集合
     * @param keyName           作为唯一标示的字段名称
     * @param parentFieldName   模型中作为parent字段名称
     * @param childrenFieldName 模型中作为children的字段名称
     */
    public static <T> List<T> fillChildren(T parent, List<T> originalList, String keyName, String parentFieldName, String childrenFieldName) throws Exception {
        List<T> childList = new ArrayList<>();
        String parentId = BeanUtils.getProperty(parent, keyName);
        for (int i = 0; i < originalList.size(); i++) {
            T t = originalList.get(i);
            String childParentId = BeanUtils.getProperty(t, parentFieldName);
            if (parentId.equals(childParentId)) {
                childList.add(t);
            }
        }
        if (!childList.isEmpty()) {
            FieldUtils.writeDeclaredField(parent, childrenFieldName, childList, true);
        }
        return childList;
    }


    /**
     * 判断是否是数字
     *
     * @param str
     * @return
     */
    public boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }


    /**
     * 查询实时表信息
     *
     * @param tableQueryDTO
     * @return
     */
    @Override
    public IPage<RealTableQueryReturnDTO> getRealTable(RealTableQueryDTO tableQueryDTO) {
        Map<String, Object> params = new HashMap<>();
        wrapRealParams(params);
        IPage<RealTableQueryReturnDTO> page = new Page<>(tableQueryDTO.getCurrent(), tableQueryDTO.getSize());
        page = bdpDataCategoryMapper.getRealTableInfo(page, tableQueryDTO, params);
        if (CollectionUtil.isEmpty(page.getRecords())) {
            return page;
        }
        for (RealTableQueryReturnDTO record : page.getRecords()) {
            ArrayList<String> strings = bdpDataCategoryMapper.selectProName(record.getId(), null);
            record.setProName(strings);
        }
        return page;
    }

    /**
     * 数据类目 项目列表查询
     */
    @Override
    public Set<ProjectListDTO> projectList() {
        Integer tenantId = ShiroUtils.getTenantId();
        Set<ProjectListDTO> proNames = new HashSet<>();
        List<BdpDataCategoryTableInfoVO> projectList = bdpDataCategoryMapper.projectList(tenantId);
        if (CollectionUtil.isEmpty(projectList)) {
            return proNames;
        }
        for (BdpDataCategoryTableInfoVO bdpDataCategoryTableInfoVO : projectList) {
            Set<ProjectListDTO> projectListDTOS = bdpDataCategoryMapper.selectProNameList(bdpDataCategoryTableInfoVO.getTableId());
            proNames.addAll(projectListDTOS);
        }
        return proNames;
    }

    @Override
    public List<Map> getTableByCategoryIdAndDb(Integer categoryId, String dbName) {
        Map<String, Object> params = new HashMap<>();
//        DataPermissionUtil.putDataFilter(params,
//                PermissionTypeEnum.STORE.getType(), PermissionTypeEnum.QUERY.getType());
        params.put("categoryId",categoryId);
        params.put("dbName",dbName);
        params.put("tenantId",ShiroUtils.getTenantId());
        params.put("create_per",ShiroUtils.getUserId());
        return bdpDataCategoryMapper.getTableByCategoryIdAndDb(params);
    }
}